package io.focus.mijin.zuul.ratelimit.filters;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.HttpServletRequestWrapper;
import org.springframework.cloud.netflix.zuul.util.RequestUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_30_WRAPPER_FILTER_ORDER;

/**
 * 重写zuul的Servlet30WrapperFilter
 *
 * @author 吴爱军
 * @date 2018/5/25
 */
public class RateLimitServlet30WrapperFilter extends ZuulFilter {

    private Field requestField = null;

    public RateLimitServlet30WrapperFilter() {
        this.requestField = ReflectionUtils.findField(HttpServletRequestWrapper.class,
                "req", HttpServletRequest.class);
        Assert.notNull(this.requestField,
                "HttpServletRequestWrapper.req field not found");
        this.requestField.setAccessible(true);
    }

    protected Field getRequestField() {
        return this.requestField;
    }

    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return SERVLET_30_WRAPPER_FILTER_ORDER + 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        if (request instanceof HttpServletRequestWrapper) {
            request = (HttpServletRequest) ReflectionUtils.getField(this.requestField,
                    request);
            ctx.setRequest(new RateLimitServlet30RequestWrapper(request) {
            });
        } else if (RequestUtils.isDispatcherServletRequest()) {
            // If it's going through the dispatcher we need to buffer the body
            ctx.setRequest(new RateLimitServlet30RequestWrapper(request));
        }
        return null;
    }

}